home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / mint / toswinsc.zoo / textwin.c < prev    next >
C/C++ Source or Header  |  1992-10-27  |  30KB  |  1,257 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. #include "xgem.h"
  13. #include <stdlib.h>
  14.  
  15. #define CLEARED 2        /* redrawing a cleared area */
  16.  
  17. int default_height = 10;    /* default font height (points) */
  18. int default_font = 1;        /* default font (pixels) */
  19. int align_windows = 0;        /* align windows on byte boundaries */
  20.  
  21. /* if a font doesn't define a character, use this one instead */
  22. #define DEFAULT_CHAR '?'
  23.  
  24. static void set_cwidths __PROTO((TEXTWIN *));
  25.  
  26. /* functions for converting x, y pixels to/from character coordinates */
  27. /* NOTES: these functions give the upper left corner; to actually draw
  28.  * a character, they must be adjusted down by t->cbase
  29.  * Also: char2pixel accepts out of range character/column combinations,
  30.  * but pixel2char never will generate such combinations.
  31.  */
  32. void
  33. char2pixel(t, col, row, xp, yp)
  34.     TEXTWIN *t;
  35.     int col, row;
  36.     int *xp, *yp;
  37. {
  38.     short *WIDE = t->cwidths;
  39.     int x;
  40.  
  41.     *yp = t->win->wi_y - t->offy + row * t->cheight;
  42.     if (!WIDE) {
  43.         *xp = t->win->wi_x - t->offx + col * t->cmaxwidth;
  44.     } else if (col >= t->maxx) {
  45.         *xp = t->win->wi_x + t->win->wi_w;
  46.     } else {
  47.         x = t->win->wi_x - t->offx;
  48.         while(--col >= 0) {
  49.             x += WIDE[t->data[row][col]];
  50.         }
  51.         *xp = x;
  52.     }
  53. }
  54.  
  55. void
  56. pixel2char(t, x, y, colp, rowp)
  57.     TEXTWIN *t;
  58.     int x, y, *colp, *rowp;
  59. {
  60.     int col, row, count, nextcount;
  61.     short *WIDE = t->cwidths;
  62.  
  63.     row = (y - t->win->wi_y + t->offy) / t->cheight;
  64.     x = x - t->win->wi_x + t->offx;
  65.  
  66.     if (WIDE == 0) {
  67.         col = x / t->cmaxwidth;
  68.     } else {
  69.         count = 0;
  70.         for (col = 0; col < t->maxx - 1; col++) {
  71.             nextcount = count + WIDE[t->data[row][col]];
  72.             if (count <= x && x < nextcount) break;
  73.             count = nextcount;
  74.         }
  75.     }
  76.     *rowp = row;
  77.     *colp = col;
  78. }
  79.  
  80. static void set_scroll_bars __PROTO((TEXTWIN *));
  81.  
  82. /*
  83.  * draw a (part of a) line on screen, with certain attributes (e.g.
  84.  * inverse video) indicated by "flag". (x, y) is the upper left corner
  85.  * of the box which will contain the line.
  86.  * If "force" is 1, we may assume that the screen is already cleared
  87.  * (this is done in update_screen() for us).
  88.  * SPECIAL CASE: if buf is an empty string, we clear from "x" to
  89.  * the end of the window.
  90.  */
  91. static void
  92. draw_buf(t, buf, x, y, flag, force)
  93.     TEXTWIN *t;
  94.     char *buf;
  95.     int x, y, flag, force;
  96. {
  97.     char *s, *lastnonblank;
  98.     int x2, fillcolor, textcolor;
  99.     int texteffects;
  100.     short *WIDE = t->cwidths;
  101.     int temp[4];
  102.  
  103.     fillcolor = flag & CBGCOL;
  104.     textcolor = (flag & CFGCOL) >> 4;
  105.     texteffects = (flag & CEFFECTS) >> 8;
  106.  
  107. #ifdef STIPPLE_SELECT
  108.     if (flag & CINVERSE) {    /* swap foreground and background */
  109.         x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
  110.     }
  111. #else
  112.     if (flag & (CINVERSE|CSELECTED)) {    /* swap foreground and background */
  113.         x2 = fillcolor; fillcolor = textcolor; textcolor = x2;
  114.     }
  115. #endif
  116.     x2 = x;
  117.     s = buf;
  118.     if (*s) {
  119.         lastnonblank = s-1;
  120.         while (*s) {
  121.             if (*s != ' ') lastnonblank = s;
  122.             if (WIDE)
  123.                 x2 += WIDE[*s];
  124.             else
  125.                 x2 += t->cmaxwidth;
  126.             s++;
  127.         }
  128.         lastnonblank++;
  129.         if (!(flag & CE_UNDERLINE))
  130.             *lastnonblank = 0;
  131.     } else {
  132.         x2 = t->win->wi_x + t->win->wi_w;
  133.     }
  134.  
  135.     set_wrmode(2);        /* transparent text */
  136.     if (fillcolor != 0 || (force != CLEARED)) {
  137.     /* the background may not be set correctly, so we do it here */
  138.         temp[0] = x;
  139.         temp[1] = y;
  140.         temp[2] = x2 - 1;
  141.         temp[3] = y + t->cheight - 1;
  142.         set_fillcolor(fillcolor);
  143.         set_fillstyle(1, 1);        /* fill the area completely */
  144.         v_bar(vdi_handle, temp);
  145.     }
  146.  
  147. /* skip leading blanks -- we don't need to draw them again! */
  148.     if (!(flag & CE_UNDERLINE)) {
  149.         while (*buf == ' ') {
  150.             buf++;
  151.             x += WIDE ? WIDE[' '] : t->cmaxwidth;
  152.         }
  153.     }
  154.  
  155.     if (*buf) {
  156.         set_textcolor(textcolor);
  157.         set_texteffects(texteffects);
  158.         v_gtext(vdi_handle, x, y + t->cbase, buf);
  159.     }
  160.  
  161. #ifdef STIPPLE_SELECT
  162.     if (flag & CSELECTED) {        /* put in the pattern */
  163.         set_wrmode(2);        /* 'OR' the pattern */
  164.         set_fillstyle(2, 2);
  165.         set_fillcolor(textcolor);
  166.         v_bar(vdi_handle, temp);
  167.     }
  168. #endif
  169. }
  170.  
  171. /*
  172.  * update the characters on screen between "firstline,firstcol" and 
  173.  * "lastline-1,lastcol-1" (inclusive)
  174.  * if force == 1, the redraw must occur, otherwise it occurs only for
  175.  * "dirty" characters. Note that we assume here that clipping
  176.  * rectanges and wind_update() have already been set for us.
  177.  */
  178.  
  179. static void
  180. update_chars(t, firstcol, lastcol, firstline, lastline, force)
  181.     TEXTWIN *t;
  182.     int firstcol, lastcol, firstline, lastline, force;
  183. {
  184. #define CBUFSIZ 127
  185.     UCHAR buf[CBUFSIZ+1], c;
  186.     int px, py, ax, i, cnt, flag, bufwidth;
  187.     short *WIDE = t->cwidths;
  188.     int lineforce = 0;
  189.     int curflag;
  190.  
  191. #define flushbuf()    \
  192.     {    buf[i] = 0;    \
  193.          draw_buf(t, buf, px, py, flag, lineforce); \
  194.          px += bufwidth; \
  195.          i = bufwidth = 0; \
  196.     }
  197.  
  198. /* make sure the font is set correctly */
  199.     set_font(t->cfont, t->cpoints);
  200.  
  201. /* find the place to start writing */
  202.     char2pixel(t, firstcol, firstline, &ax, &py);
  203.  
  204. /* now write the characters we need to */
  205.     while (firstline < lastline) {
  206. /* if no characters on the line need re-writing, skip the loop */
  207.         if (!force && t->dirty[firstline] == 0) {
  208.             py += t->cheight;
  209.             firstline++;
  210.             continue;
  211.         }
  212.         px = ax;
  213. /*
  214.  * now, go along collecting characters to write into the buffer
  215.  * we add a character to the buffer if and only if (1) the
  216.  * character's attributes (inverse video, etc.) match the
  217.  * attributes of the character already in the buffer, and
  218.  * (2) the character needs redrawing. Otherwise, if there are
  219.  * characters in the buffer, we flush the buffer.
  220.  */
  221.         i = bufwidth = 0;
  222.         cnt = firstcol;
  223.         flag = 0;
  224.         lineforce = force;
  225.         if (!lineforce && (t->dirty[firstline] & ALLDIRTY))
  226.             lineforce = 1;
  227.         while (cnt < lastcol) {
  228.             c = t->data[firstline][cnt];
  229.             if (lineforce ||
  230.                (t->cflag[firstline][cnt] & (CDIRTY|CTOUCHED))) {
  231. /* yes, this character needs drawing */
  232. /* if the font is proportional and the character has really changed,
  233.  * then all remaining characters will have to be redrawn, too
  234.  */
  235.             if (WIDE && (lineforce == 0) &&
  236.                 (t->cflag[firstline][cnt] & CDIRTY))
  237.                 lineforce = 1;
  238. /* watch out for characters that can't be drawn in this font */
  239.             if (c < t->minADE || c > t->maxADE)
  240.                 c = DEFAULT_CHAR;
  241.             curflag = t->cflag[firstline][cnt] & ~(CDIRTY|CTOUCHED);
  242.             if (flag == curflag) {
  243.                 buf[i++] = c;
  244.                 bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
  245.                 if (i == CBUFSIZ) {
  246.                 flushbuf();
  247.                 }
  248.             } else {
  249.                 if (i) {
  250.                 flushbuf();
  251.                 }
  252.                 flag = curflag;
  253.                 buf[i++] = c;
  254.                 bufwidth += (WIDE ? WIDE[c] : t->cmaxwidth);
  255.             }
  256.             } else {
  257.             if (i) {
  258.                 flushbuf();
  259.             }
  260.             px += (WIDE ? WIDE[c] : t->cmaxwidth);
  261.             }
  262.             cnt++;
  263.         }
  264.         if (i) {
  265.             flushbuf();
  266.         }
  267.         if (WIDE) {        /* the line's 'tail' */
  268.             draw_buf(t, "", px, py, t->cflag[firstline][t->maxx-1],
  269.                 lineforce);
  270.         }
  271.         py += t->cheight;
  272.         firstline++;
  273.     }
  274. }
  275.  
  276. /*
  277.  * mark_clean: mark a window as having been completely updated
  278.  */
  279.  
  280. void
  281. mark_clean(t)
  282.     TEXTWIN *t;
  283. {
  284.     int line, col;
  285.  
  286.     for (line = 0; line < t->maxy; line++) {
  287.         if (t->dirty[line] == 0)
  288.             continue;
  289.         for (col = 0; col < t->maxx; col++) {
  290.             t->cflag[line][col] &= ~(CDIRTY|CTOUCHED);
  291.         }
  292.         t->dirty[line] = 0;
  293.     }
  294. }
  295.  
  296. /*
  297.  * redraw all parts of window v which are contained within the
  298.  * given rectangle. Assumes that the clipping rectange has already
  299.  * been set correctly.
  300.  * NOTE: more than one rectangle may cover the same area, so we
  301.  * can't mark the window clean during the update; we have to do
  302.  * it in a separate routine (mark_clean)
  303.  */
  304.  
  305. static MFDB scr_mfdb;    /* left NULL so it refers to the screen by default */
  306.  
  307. stat